package vsvm.data.filter.ranking;


import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;

import vsvm.math.statistics.Characteristics;


public class Soap extends AbstractSupervisedRanking 
{	
	private static final long serialVersionUID = 100L;
	private Comparator<double[][]> comp = null;
	
	public Soap()
	{
		comp = new DoubleDoubleComparator();
	}
	
	private ArrayList<double[][]> sort(double[] attr, int numVec, double[] labels)
	{
		ArrayList<double[][]> tmplist = new ArrayList<double[][]>();
		for(int i = 0; i < numVec; i++)
		{
			double[][] tmp = new double[1][2];
			tmp[0][0] = attr[i];
			tmp[0][1] = labels[i];
			tmplist.add(tmp);
				
		}
		Collections.sort(tmplist, comp);

		return tmplist;
	}

	public double[] score() 
	{		
		int numAttr = dataModel.getAttributeCount();
		int numVec = dataModel.getVectorCount();
		double[] labels = allFeatureValues(dataModel.getClassAttributeIndex());
		
		double[] scores = new double[numAttr];
		
		for(int i = 0; i < numAttr; i++)
		{
			scores[i] = numberChanges(sort(allFeatureValues(i), numVec, labels));
		}
		
		double max = Characteristics.getMax(scores);

		for(int t = 0; t < scores.length; t++)
		{
			scores[t] = max - scores[t];
		}
				
		return scores;
	}
	
	private int numberChanges(ArrayList<double[][]> tmp)
	{
		int changes = 0; 
		int i = 0; 
		int m = 0;
		
		while(i < tmp.size() - 1)
		{
			double label = tmp.get(i)[0][1];
			double value = tmp.get(i)[0][0];
			m = i + 1;
			
			if(value == tmp.get(m)[0][0])
			{				
				ArrayList<double[][]> seq = new ArrayList<double[][]>();
				int nelem = 1;
				seq.add(tmp.get(i));
				
				while(m < tmp.size() && value == tmp.get(m)[0][0])
				{
					seq.add(tmp.get(m));
					nelem++;
					m++;	
				}
				
				int rfi = changesSameValue(seq);
				if(rfi > nelem/2)
				{
					changes = changes + (nelem - rfi) * 2;	
				}
				else
				{
					changes = changes + nelem - 1;	
				}
			} 
			else if(i - 1 > 0)
			{
				if(label != tmp.get(i - 1)[0][1])
				{
					changes++;
				}
			}
			i = m;
		}

		return changes;
	}
	
	private int changesSameValue(ArrayList<double[][]> sequence)
	{
		int n = 0;
		HashSet<Double> labels = new HashSet<Double>();
		
		for(int i = 0; i < sequence.size(); i++)
		{
			double label = sequence.get(i)[0][1];
			if(!labels.contains(label))
			{
				labels.add(label);
				int m = 0; int count = 0;
				while(m < sequence.size())
				{
					if(label == sequence.get(m)[0][1])
					{
						count++;
					}												
					m++;
				}
				if(count > n)
				{
					n = count;	
				}
			}			
		}

		return n;
	}

}

class DoubleDoubleComparator implements Comparator<double[][]>, Serializable 
{

    /**
	 * 
	 */
	private static final long serialVersionUID = 100L;

	public int compare(double[][] a, double[][] b) 
    {
        if (a[0][0] < b[0][0]) 
        {
            return -1;
        } 
        else if (a[0][0] == b[0][0]) 
        {
            return 0;
        } 
        else 
        {
            return 1;
        }
    }
}

